package com.streamer.app.utils

import android.content.Context
import android.os.Build
import android.util.Log
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import info.mqtt.android.service.MqttAndroidClient
import org.eclipse.paho.client.mqttv3.*
import java.util.*

class MqttManager private constructor() {
    
    companion object {
        private const val TAG = "MqttManager"
        private const val SERVER_URI = "wss://api.live71.xinzhidi.cn:8084/mqtt"
        private const val USERNAME = "admin"  // 使用实际的MQTT用户名
        private const val PASSWORD = "admin123"  // 使用实际的MQTT密码
        private const val CLIENT_ID_PREFIX = "android_client_"
        
        @Volatile
        private var INSTANCE: MqttManager? = null
        
        fun getInstance(): MqttManager {
            return INSTANCE ?: synchronized(this) {
                INSTANCE ?: MqttManager().also { INSTANCE = it }
            }
        }
    }
    
    private var mqttClient: MqttAndroidClient? = null
    private var isConnected = false
    private val messageCallbacks = mutableListOf<MessageCallback>()
    
    interface MessageCallback {
        fun onMessageReceived(topic: String, message: String)
        fun onConnectionStatusChanged(connected: Boolean)
    }
    
    fun addMessageCallback(callback: MessageCallback) {
        if (!messageCallbacks.contains(callback)) {
            messageCallbacks.add(callback)
        }
    }
    
    fun removeMessageCallback(callback: MessageCallback) {
        messageCallbacks.remove(callback)
    }
    
    fun connect(context: Context, clientId: String, onResult: ((Boolean, String?) -> Unit)? = null) {
        if (isConnected) {
            Log.d(TAG, "MQTT already connected")
            onResult?.invoke(true, "Already connected")
            return
        }
        
        try {
            Log.d(TAG, "Starting MQTT connection...")
            Log.d(TAG, "Server URI: $SERVER_URI")
            Log.d(TAG, "Client ID: $clientId")
            Log.d(TAG, "Username: $USERNAME")
            
            // Check Android version compatibility
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                Log.d(TAG, "Running on Android S+ (API 31+), using compatibility mode")
            }
            
            // 确保客户端ID是唯一的
            val uniqueClientId = if (clientId.isNotEmpty()) {
                "$CLIENT_ID_PREFIX$clientId"
            } else {
                "$CLIENT_ID_PREFIX${System.currentTimeMillis()}"
            }
            
            mqttClient = MqttAndroidClient(context, SERVER_URI, uniqueClientId)
            
            val options = MqttConnectOptions().apply {
                isCleanSession = true
                userName = USERNAME
                password = PASSWORD.toCharArray()
                connectionTimeout = 30
                keepAliveInterval = 60
                isAutomaticReconnect = true
                // 添加更多连接选项
                isHttpsHostnameVerificationEnabled = false
                mqttVersion = MqttConnectOptions.MQTT_VERSION_3_1_1
            }
            
            Log.d(TAG, "Attempting to connect with options: cleanSession=${options.isCleanSession}, timeout=${options.connectionTimeout}")
            
            mqttClient?.connect(options, null, object : IMqttActionListener {
                override fun onSuccess(asyncActionToken: IMqttToken?) {
                    Log.d(TAG, "MQTT connected successfully")
                    isConnected = true
                    notifyConnectionStatusChanged(true)
                    onResult?.invoke(true, "Connected successfully")
                }
                
                override fun onFailure(asyncActionToken: IMqttToken?, exception: Throwable?) {
                    Log.e(TAG, "MQTT connection failed: ${exception?.message}")
                    Log.e(TAG, "Exception type: ${exception?.javaClass?.simpleName}")
                    Log.e(TAG, "Exception cause: ${exception?.cause?.message}")
                    isConnected = false
                    notifyConnectionStatusChanged(false)
                    onResult?.invoke(false, exception?.message ?: "Connection failed")
                }
            })
            
            // 设置消息回调
            mqttClient?.setCallback(object : MqttCallbackExtended {
                override fun connectComplete(reconnect: Boolean, serverURI: String?) {
                    Log.d(TAG, "MQTT connect complete, reconnect: $reconnect")
                }
                
                override fun connectionLost(cause: Throwable?) {
                    Log.e(TAG, "MQTT connection lost: ${cause?.message}")
                    isConnected = false
                    notifyConnectionStatusChanged(false)
                }
                
                override fun messageArrived(topic: String?, message: MqttMessage?) {
                    message?.let {
                        val messageString = String(it.payload)
                        notifyMessageReceived(topic ?: "", messageString)
                    }
                }
                
                override fun deliveryComplete(token: IMqttDeliveryToken?) {
                    Log.d(TAG, "MQTT delivery complete")
                }
            })
            
        } catch (e: Exception) {
            Log.e(TAG, "MQTT connection error: ${e.message}")
            onResult?.invoke(false, e.message)
        }
    }
    
    fun disconnect() {
        try {
            mqttClient?.disconnect(null, object : IMqttActionListener {
                override fun onSuccess(asyncActionToken: IMqttToken?) {
                    Log.d(TAG, "MQTT disconnected successfully")
                    isConnected = false
                    notifyConnectionStatusChanged(false)
                }
                
                override fun onFailure(asyncActionToken: IMqttToken?, exception: Throwable?) {
                    Log.e(TAG, "MQTT disconnect failed: ${exception?.message}")
                }
            })
        } catch (e: Exception) {
            Log.e(TAG, "MQTT disconnect error: ${e.message}")
        }
    }
    
    fun subscribe(topic: String, qos: Int = 1, onResult: ((Boolean, String?) -> Unit)? = null) {
        if (!isConnected) {
            onResult?.invoke(false, "Not connected")
            return
        }
        
        try {
            mqttClient?.subscribe(topic, qos, null, object : IMqttActionListener {
                override fun onSuccess(asyncActionToken: IMqttToken?) {
                    Log.d(TAG, "Subscribed to topic: $topic")
                    onResult?.invoke(true, "Subscribed successfully")
                }
                
                override fun onFailure(asyncActionToken: IMqttToken?, exception: Throwable?) {
                    Log.e(TAG, "Subscribe failed for topic $topic: ${exception?.message}")
                    onResult?.invoke(false, exception?.message)
                }
            })
        } catch (e: Exception) {
            Log.e(TAG, "Subscribe error for topic $topic: ${e.message}")
            onResult?.invoke(false, e.message)
        }
    }
    
    fun unsubscribe(topic: String, onResult: ((Boolean, String?) -> Unit)? = null) {
        if (!isConnected) {
            onResult?.invoke(false, "Not connected")
            return
        }
        try {
            mqttClient?.unsubscribe(topic, null, object : IMqttActionListener {
                override fun onSuccess(asyncActionToken: IMqttToken?) {
                    Log.d(TAG, "Unsubscribed from topic: $topic")
                    onResult?.invoke(true, null)
                }
                override fun onFailure(asyncActionToken: IMqttToken?, exception: Throwable?) {
                    Log.e(TAG, "Unsubscribe failed for topic $topic: ${exception?.message}")
                    onResult?.invoke(false, exception?.message)
                }
            })
        } catch (e: Exception) {
            Log.e(TAG, "Unsubscribe error for topic $topic: ${e.message}")
            onResult?.invoke(false, e.message)
        }
    }
    
    fun publish(topic: String, message: String, qos: Int = 1, onResult: ((Boolean, String?) -> Unit)? = null) {
        if (!isConnected) {
            onResult?.invoke(false, "Not connected")
            return
        }
        
        try {
            val mqttMessage = MqttMessage(message.toByteArray())
            mqttMessage.qos = qos
            
            mqttClient?.publish(topic, mqttMessage, null, object : IMqttActionListener {
                override fun onSuccess(asyncActionToken: IMqttToken?) {
                    Log.d(TAG, "Message published to topic: $topic")
                    onResult?.invoke(true, "Published successfully")
                }
                
                override fun onFailure(asyncActionToken: IMqttToken?, exception: Throwable?) {
                    Log.e(TAG, "Publish failed for topic $topic: ${exception?.message}")
                    onResult?.invoke(false, exception?.message)
                }
            })
        } catch (e: Exception) {
            Log.e(TAG, "Publish error for topic $topic: ${e.message}")
            onResult?.invoke(false, e.message)
        }
    }
    
    fun isConnected(): Boolean = isConnected
    
    private fun notifyMessageReceived(topic: String, message: String) {
        CoroutineScope(Dispatchers.Main).launch {
            messageCallbacks.forEach { callback ->
                try {
                    callback.onMessageReceived(topic, message)
                } catch (e: Exception) {
                    Log.e(TAG, "Error in message callback: ${e.message}")
                }
            }
        }
    }
    
    private fun notifyConnectionStatusChanged(connected: Boolean) {
        CoroutineScope(Dispatchers.Main).launch {
            messageCallbacks.forEach { callback ->
                try {
                    callback.onConnectionStatusChanged(connected)
                } catch (e: Exception) {
                    Log.e(TAG, "Error in connection status callback: ${e.message}")
                }
            }
        }
    }
} 